package com.spa.application.service.admin;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spa.application.config.massagist.ProfitRule;
import com.spa.application.dto.PageResult;
import com.spa.application.dto.admin.FinanceOrderListDTO;
import com.spa.application.dto.admin.FinanceOrderListExportDTO;
import com.spa.application.query.admin.FinanceOrderQuery;
import com.spa.domain.entity.*;
import com.spa.domain.service.*;
import com.spa.infrastructure.enums.dict.SourceEnum;
import com.spa.infrastructure.mapper.OrderMapperStruct;
import com.spa.infrastructure.repository.condition.MassagistWithdrawRecordCondition;
import com.spa.infrastructure.repository.condition.OrderInfoCondition;
import com.spa.infrastructure.repository.condition.ShopWithdrawRecordCondition;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 财务管理相关
 */
@Service
@Slf4j
public class FinanceApplicationService {

    @Autowired
    private OrderService orderService;

    @Autowired
    private MassagistWithdrawRecordService massagistWithdrawRecordService;

    @Autowired
    private ShopWithdrawRecordService shopWithdrawRecordService;

    @Autowired
    private ProfitService profitService;

    @Autowired
    private CouponService couponService;

    public PageResult<FinanceOrderListDTO> page(FinanceOrderQuery query) {
        OrderInfoCondition condition = OrderMapperStruct.INSTANCE.query2Condition(query);
        OrderService.OrderInfoPlug plug = OrderService.OrderInfoPlug.base();
        plug.setTicket(true);
        plug.setEvaluate(true);
        plug.setTrade(true);
        Page<OrderInfo> orderInfoPage = orderService.pageByCondition(condition, plug);
        PageResult<FinanceOrderListDTO> financeOrderListDTOPageResult =
                OrderMapperStruct.INSTANCE.entity2FinanceOrderListDTO4Page(orderInfoPage);
        searchByOrder(financeOrderListDTOPageResult.getRecords());
        return financeOrderListDTOPageResult;
    }

    /**
     * 默认就是查找全部订单
     * 订单编号、门店、订单状态、服务技师、下单时间
     */
    private void searchByOrder(List<FinanceOrderListDTO> financeOrderListDTOList) {
        List<Long> massagistWithdrawIds = financeOrderListDTOList.stream().map(FinanceOrderListDTO::getMassagistWithdrawId).toList();
        MassagistWithdrawRecordCondition massagistWithdrawRecordCondition = new MassagistWithdrawRecordCondition();
        massagistWithdrawRecordCondition.setIds(massagistWithdrawIds);
        List<MassagistWithdrawRecord> massagistWithdrawRecords = massagistWithdrawRecordService.list(massagistWithdrawRecordCondition);
        Map<Long, MassagistWithdrawRecord> massagistWithdrawRecordMap =
                massagistWithdrawRecords.stream().collect(Collectors.toMap(MassagistWithdrawRecord::getId, Function.identity()));
        List<Long> shopWithdrawIds = financeOrderListDTOList.stream().map(FinanceOrderListDTO::getShopWithdrawId).toList();
        ShopWithdrawRecordCondition shopWithdrawRecordCondition = new ShopWithdrawRecordCondition();
        shopWithdrawRecordCondition.setIds(shopWithdrawIds);
        List<ShopWithdrawRecord> shopWithdrawRecords = shopWithdrawRecordService.list(shopWithdrawRecordCondition);
        Map<Long, ShopWithdrawRecord> shopWithdrawRecordMap =
                shopWithdrawRecords.stream().collect(Collectors.toMap(ShopWithdrawRecord::getId, Function.identity()));
        List<Long> orderIds = financeOrderListDTOList.stream().map(FinanceOrderListDTO::getOrderId).toList();
        Map<Long, List<Profit>> profitMap = new HashMap<>();
        if (!orderIds.isEmpty()) {
            List<Profit> profitList = profitService.queryProfitByOrderIds(orderIds);
            profitMap = profitList.stream().collect(Collectors.groupingBy(Profit::getOrderId));
        }
        for (FinanceOrderListDTO record : financeOrderListDTOList) {
            record.setTotalPrice(record.getServicePrice() + record.getExtPrice() + record.getTravelPrice());
            int ticketPrice = ObjectUtil.isNotNull(record.getTicketPrice()) ? record.getTicketPrice() : 0;
            record.setPayPrice(record.getTotalPrice() - ticketPrice);
            record.setPayRate("0.54%");
            record.setPayCommission(record.getPayPrice() * 0.0054);
            MassagistWithdrawRecord massagistWithdrawRecord = massagistWithdrawRecordMap.get(record.getMassagistWithdrawId());
            if (ObjectUtil.isNotNull(massagistWithdrawRecord)) {
                record.setMassagistWithdrawStatus(massagistWithdrawRecord.getStatus());
                record.setMassagistWithdrawPrice(massagistWithdrawRecord.getAmount());
                record.setMassagistWithdrawTime(massagistWithdrawRecord.getApplyTime());
            }
            ShopWithdrawRecord shopWithdrawRecord = shopWithdrawRecordMap.get(record.getShopWithdrawId());
            if (ObjectUtil.isNotNull(shopWithdrawRecord)) {
                record.setShopWithdrawStatus(shopWithdrawRecord.getStatus());
                record.setShopWithdrawPrice(shopWithdrawRecord.getAmount());
                record.setShopWithdrawTime(shopWithdrawRecord.getApplyTime());
            }
            List<Profit> profitList = profitMap.get(record.getOrderId());
            if (CollectionUtil.isNotEmpty(profitList)) {
                List<Profit> profits = profitList.stream().filter(profit1 -> profit1.getOrderType() == 1).toList();
                List<Profit> profits1 = profitList.stream().filter(profit1 -> profit1.getOrderType() == 3).toList();
                if (CollectionUtil.isNotEmpty(profits)) {
                    int massagistCommissionSharingPrice = profitList.stream().map(Profit::getMassagistIncome).reduce(Integer::sum).orElse(0);
                    int shopCommissionSharingPrice = profitList.stream().map(Profit::getShopIncome).reduce(Integer::sum).orElse(0);
                    int platformCommissionSharingPrice = profitList.stream().map(Profit::getAdminIncome).reduce(Integer::sum).orElse(0);
                    Profit profit = profits.get(0);
                    ProfitRule profitRule = JSONUtil.toBean(profit.getRuleData(), ProfitRule.class);
                    record.setMassagistCommissionSharingProportion(profitRule.getMassagistPercent());
                    record.setMassagistCommissionSharingPrice(massagistCommissionSharingPrice);
                    record.setMassagistTotalPrice(massagistCommissionSharingPrice + record.getTravelPrice());
                    record.setShopCommissionSharingProportion(profitRule.getShopPercent());
                    record.setShopCommissionSharingPrice(shopCommissionSharingPrice);
                    record.setPlatformCommissionSharingProportion(profitRule.getAdminPercent());
                    record.setPlatformCommissionSharingPrice(platformCommissionSharingPrice);
                    record.setPlatformActualPrice(platformCommissionSharingPrice - record.getPayCommission());
                }
                if (CollectionUtil.isNotEmpty(profits1)) {
                    int travelPriceCancel = profits1.stream().map(Profit::getTravelPrice).reduce(Integer::sum).orElse(0);
                    record.setMassagistTotalPrice(travelPriceCancel);
                }
            }
            List<Coupon> coupons = couponService.getCouponsByOrderId(record.getOrderId());
            if (CollUtil.isNotEmpty(coupons)) {
                int couponPrice =coupons.get(0).getServicePrice() * coupons.size();
                record.setSource(SourceEnum.byCode(coupons.get(0).getSource()).getDesc());
                record.setPayPrice(record.getTotalPrice() - ticketPrice - couponPrice);
                record.setPayCommission(record.getPayPrice() * 0.0054);
            }
        }
    }

    public List<FinanceOrderListExportDTO> list(FinanceOrderQuery query) {
        OrderInfoCondition condition = OrderMapperStruct.INSTANCE.query2Condition(query);
        List<OrderInfo> orderInfoList = orderService.orderList(condition);
        List<FinanceOrderListDTO> financeOrderListDTOList =
                OrderMapperStruct.INSTANCE.entity2FinanceOrderListDTO4List(orderInfoList);
        try {
            searchByOrder(financeOrderListDTOList);
        } catch (Throwable throwable) {
            log.error("export Throwable ",throwable);
        }
        return OrderMapperStruct.INSTANCE.dto2FinanceOrderListExportDTO4List(financeOrderListDTOList);
    }

}
